/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.jili.ubert.netty.priceserver;

import com.jili.ubert.code.ReturnIDEntity;
import com.jili.ubert.code.client2server.Login;
import com.jili.ubert.code.client2server.Logout;
import com.jili.ubert.code.client2server.RegistPriceMsg;
import com.jili.ubert.code.server2client.MsgResult;
import com.jili.ubert.netty.MsgEntity;
import com.jili.ubert.netty.VerifyCodeGenerator;
import com.jili.ubert.server.datapool.DataPoolPrice;
import com.jili.ubert.server.priceserver.PriceServer;
import com.jili.ubert.server.publicdata.PublicData;
import com.jili.ubert.tool.IPv4Util;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author ChengJiLi
 */
public class PriceHanlder extends SimpleChannelInboundHandler<MsgEntity> {

    private static final Log log = LogFactory.getLog(PriceHanlder.class);
    private DataPoolPrice datapool;
    private PublicData publicData;
    private PriceServer priceServer;

    PriceHanlder(DataPoolPrice datapool, PublicData publicData,PriceServer priceServer) {
        this.publicData = publicData;
        this.datapool = datapool;
        this.priceServer=priceServer;
    }

    private boolean isBlackList(int ip, String mac) {
        if (this.publicData.getForbidUser().containsKey(String.valueOf(ip))) {
            return true;
        }
        if (this.publicData.getForbidUser().containsKey(mac)) {
            return true;
        }
        return this.publicData.getForbidUser().containsKey(ip + mac);
    }

    private boolean isBlackList(String user) {
        return this.publicData.getForbidUser().containsKey(user);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        if (ctx.channel().isActive()) {
            ctx.channel().writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        } else {
            ctx.close();
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
            throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                ctx.close();
                log.info("READER_IDLE 读超时");
            } else if (e.state() == IdleState.WRITER_IDLE) {
                log.info("WRITER_IDLE 写超时");
            }
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void channelActive(final ChannelHandlerContext ctx) {
        log.info("新增登陆连接：" + ctx.channel());
    }

    @Override
    protected void messageReceived(ChannelHandlerContext ctx, MsgEntity msg) throws Exception {
        if (msg == null) {
            return;
        }
        log.debug("messageReceived" + ctx);
        Channel channel = ctx.channel();
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        int ip = IPv4Util.bytesToInt(insocket.getAddress().getAddress());
        log.debug("客户IP：" + insocket.getAddress().getHostAddress() + "-" + ip);
        //    String mac = IPv4Util.getMACAddress(insocket.getAddress());
        String mac = "WE-WE-WE-WE-WE";
        //防止攻击，过滤类（现在一个算法）
        if (this.isBlackList(ip, mac)) {
            MsgResult rst = ReturnIDEntity.forbidInblacklist;
            msg.Reply(250, rst.EnCode(rst));
            channel.close();
            return;
        }
        int csCommondCode = msg.getCmdCode();
        byte[] data = msg.getData();
        switch (csCommondCode) {
            case 0: {//启动问候，请求验证码，回复验证码
                String str = VerifyCodeGenerator.GenerateVerifyCode(4);
                log.debug("0-回应" + ip + " 验证码：" + str);
                msg.Reply(0, str.getBytes());
                log.debug("1-回应" + ip + " 验证码：" + str);
                break;
            }
            case 1: {//登录  Login
                /*
                 1.验证密码，验证码；回复消息
                 2.维护用户登录列表
                
                 备注现在为了提升用户体验，用户在输入的时候验证有没有，验证码也在输入的时候验证正确不正确。
                 */
                //解码消息
                Login login = new Login();
                login = login.DeCode(data);
                MsgResult rst = publicData.LoginCheck(login, ip, channel);
                msg.Reply(1, rst.EnCode(rst));
                break;
            }
            case 2: {//登出 Logout
                /*
                 1.从用户登录列表删除
                 2.释放其他资源
                 */
                Logout lonout = new Logout();
                lonout = lonout.DeCode(data);
                MsgResult rst = publicData.Logout(lonout.getUserID(), ip);
                msg.Reply(2, rst.EnCode(rst));
                break;
            }
            case 3: {
                publicData.WorkRun(new Runnable() {
                    @Override public void run() {
                        try {
                            RegistPriceMsg rp = RegistPriceMsg.DeCode(data);
                            priceServer.dealRegister(rp,channel);
                        } catch (IOException ex) {
                            Logger.getLogger(PriceHanlder.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                });
            }
            case 4: {
                publicData.WorkRun(new Runnable() {
                    @Override public void run() {
                        try {
                            RegistPriceMsg rp = RegistPriceMsg.DeCode(data);
                            priceServer.dealCancelRegister(rp,channel);
                        } catch (IOException ex) {
                            Logger.getLogger(PriceHanlder.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                });
            }
            case 5: {
                publicData.WorkRun(new Runnable() {
                    @Override public void run() {
                            priceServer.dealCancelRegister(channel);
                    }
                });
            }
            default: {

            }
        }
    }

}
